package com.ym521.logdog.engine

import com.ym521.logdog.core.DefaultLogDogConfig
import com.ym521.logdog.core.ILogDogFormatEngine

/**
 * @author YM
 * @E-mail 2435970206@qq
 * @QQ 2435970206
 * Logg格式引擎
 */
internal class LogDogFormatEngine private constructor() : ILogDogFormatEngine {
    companion object {
        /**
         *  固定偏移位置
         *  经过测试得到的最后的固定值 9
         */
        private const val methodOffset = 9

        /**
         *  固定换行字符个数
         */
        private const val LINDE_MAX_CHAR = 120

        /**
         * 经过测试 2*1000 可以兼容全汉字打印，避免截断乱码的问题
         * 一次最大打印 2*1000长度个字符
         */
        private const val MAX_PRINT_COUNT = 2 * 1000

        fun build(): ILogDogFormatEngine {
            return LogDogFormatEngine()
        }
    }

    //换行(空行)
    private val WRAP = System.getProperty("line.separator", "\n") ?: "\n"
    private val WRAP_LINE = " $WRAP"

    //开始符
    private val START_CHAR =
        "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━start━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓${WRAP}"

    //中间分割符
    private val CONTENT_CHAR =
        "┣┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┫${WRAP}"

    //结束符
    private val END_CHAR =
        "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━end━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛${WRAP}"


    override fun formatGenerate(body: String, printlnLog: (log: String) -> Unit) {
        val currentThread = Thread.currentThread()
        val logContentBuilder = StringBuilder()
        logContentBuilder.append(WRAP_LINE)
        logContentBuilder.append(START_CHAR)
        //头部
        if (DefaultLogDogConfig.isShowThreadInfo) {
            logContentBuilder.append(
                "${lineSpaceChar()}currentThread: ${currentThread.name}$WRAP"
            )
            logContentBuilder.append(CONTENT_CHAR)
        }
        //颈部
        if (DefaultLogDogConfig.isShowMethod && DefaultLogDogConfig.showMethodCount > 0) {
            val methodContent = currentMethodsInfo(DefaultLogDogConfig.showMethodCount)
            logContentBuilder.append(methodContent)
            logContentBuilder.append(CONTENT_CHAR)
        }
        //体部
        val contentBody = StringBuilder(body)
        if (DefaultLogDogConfig.isWrap)
            maxLineHandler(contentBody)
        logContentBuilder.append("$contentBody $WRAP")
        logContentBuilder.append(END_CHAR)
        toFormatLog(logContentBuilder, printlnLog)
    }

    private fun toFormatLog(logFormat: StringBuilder, printlnLog: (log: String) -> Unit) {
        val length = logFormat.length
        if (length > MAX_PRINT_COUNT) {
            val printCount = length / MAX_PRINT_COUNT
            for (index in 0 until printCount) {
                val logPartial = logFormat.substring(
                    index * MAX_PRINT_COUNT,
                    (1 + index) * MAX_PRINT_COUNT
                ).toString()
                val logPartialFormat = "${if (index == 0) "" else WRAP_LINE}$logPartial"
                printlnLog(logPartialFormat)
            }
            if (length > printCount * MAX_PRINT_COUNT) {
                val logPartial = logFormat.substring(printCount * MAX_PRINT_COUNT).toString()
                val logPartialFormat = "$WRAP_LINE$logPartial"
                printlnLog(logPartialFormat)
            }
        } else {
            val logPartialFormat = logFormat.toString()
            printlnLog(logPartialFormat)
        }
    }

    /**
     * 方法信息
     */
    private fun currentMethodsInfo(methodCount: Int): String {
        val mStackTrace = Thread.currentThread().stackTrace
        val methodInfoBuilder = StringBuilder()
        var methodNum = 0
        val offset = methodOffset + DefaultLogDogConfig.extraOffset
        for (index in offset until mStackTrace.size) {
            if (methodNum == methodCount) {
                break
            }
            val stackTrace = mStackTrace[index]
            val className = stackTrace.className.let {
                val lastIndex = it.lastIndexOf(".")
                it.substring(lastIndex + 1)
            }
            methodInfoBuilder.insert(
                0,
                "${lineSpaceChar(methodCount - methodNum)}${stackTrace.className}.${stackTrace.methodName}(${className}:${stackTrace.lineNumber}) $WRAP"
            )
            methodNum++
        }
        return methodInfoBuilder.toString()
    }

    /**
     * 换行处理
     */
    private fun maxLineHandler(content: StringBuilder) {
        val length = content.length
        if (length > LINDE_MAX_CHAR) {
            val count = length / LINDE_MAX_CHAR
            for (i in 1..count) {
                val searchIndex = if (i > 1) 1 + (LINDE_MAX_CHAR * (i - 1)) else 0
                val si = content.indexOf(WRAP, searchIndex)
                if (si == -1 || si > i * LINDE_MAX_CHAR) {
                    content.insert(i * LINDE_MAX_CHAR, WRAP)
                }
            }
        }
    }

    /**
     * 换行符
     */
    private fun lineSpaceChar(count: Int = 1): String {
        var stanceChars = ""
        for (i in 0 until count) {
            stanceChars += "    "
        }
        return stanceChars
    }
}